﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Data;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using CodeLibrary.NativeMethods.Native;
using Microsoft.Win32;
using CodeLibrary.NativeMethods.Utils;

namespace CodeLibrary.ApplicationHoster
{
    [ProgId("CodeLibrary.ApplicationHoster")]
    [ComVisible(true)]
    [Guid("B91FA855-CBD5-435C-B910-D494E007ADE3")]
    [ClassInterface(ClassInterfaceType.AutoDual)]
    public partial class ApplicationHoster : UserControl
    {
        public ApplicationHoster()
        {
            InitializeComponent();
            lblStatus.Text = "控件装载完成";
        }

        private string _manifest;
        private IntPtr _hWndChild;

        [ComVisible(true)]
        public string Manifest
        {
            get { return _manifest; }
            set
            {
                _manifest = value;
                lblStatus.Text = string.Format("装载应用程序[{0}]", _manifest);
                HostApplication();
                lblStatus.Text = string.Format("完成装载[{0}]", _manifest);
            }
        }

        private void HostApplication()
        {
            if (!File.Exists(Manifest))
            {
                return;
            }
            try
            {
                Process p = ExecuteProgram();
                p.WaitForInputIdle(10000);
                _hWndChild = p.MainWindowHandle;
                User32Utils.SetParent(_hWndChild, Handle);
                User32Utils.SetWindowLong(_hWndChild, NativeConsts.GWL_STYLE, NativeConsts.WS_VISIBLE);
                User32Utils.MoveWindow(_hWndChild, 0, 0, Width, Height, true);
            }
            catch(Exception exception)
            {
                MessageBox.Show(exception.Message);
            }
        }


        private Process ExecuteProgram()
        {
            var p = new Process();
            p.StartInfo.FileName = Manifest;
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardInput = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.CreateNoWindow = true;
            p.Start();
            return p;
        }

        [ComRegisterFunction]
        public static void RegisterClass(string key)
        {
            StringBuilder sb = new StringBuilder(key);
            sb.Replace(@"HKEY_CLASSES_ROOT\", "");
            RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true);
            Debug.Assert(k != null, "k != null");

            RegistryKey ctrl = k.CreateSubKey("Control");
            Debug.Assert(ctrl != null, "ctrl != null");
            ctrl.Close();

            RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true);
            Debug.Assert(inprocServer32 != null, "inprocServer32 != null");
            inprocServer32.SetValue("CodeBase", Assembly.GetExecutingAssembly().CodeBase);
            inprocServer32.Close();

            k.Close();
        }

        [ComUnregisterFunction]
        public static void UnregisterClass(string key)
        {
            StringBuilder sb = new StringBuilder(key);
            sb.Replace(@"HKEY_CLASSES_ROOT\", "");

            RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true);
            Debug.Assert(k != null, "k != null");
            k.DeleteSubKey("Control", false);
            k.OpenSubKey("InprocServer32", true);
            k.DeleteSubKey("CodeBase", false);
            k.Close();
        }

        private void ApplicationHoster_SizeChanged(object sender, EventArgs e)
        {
            if (_hWndChild != IntPtr.Zero)
            {
                User32Utils.MoveWindow(_hWndChild, 0, 0, Width, Height, true);
            }
            base.OnResize(e);
        }

        protected override void OnHandleDestroyed(EventArgs e)
        {
            if (_hWndChild != IntPtr.Zero)
			{
                User32Utils.PostMessage(_hWndChild, NativeConsts.WM_CLOSE, 0, 0);
				System.Threading.Thread.Sleep(1000);
                _hWndChild = IntPtr.Zero;
			}
            base.OnHandleDestroyed(e);
        }
    }
}
